package org.massdeception.gcal.notifytracker;

import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.massdeception.gcal.notifytracker.config.NotifyTrackerConfig;

import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.extensions.Reminder;
import com.google.gdata.data.extensions.When;
import com.google.gdata.data.extensions.Reminder.Method;

public class NotifiyTracker
{
    private static String APPLICATION_NAME = "massdeception_notify_tracker";
    
    private static String [] exclude;

    private static int checkInterval = 3600;
    
    private static String CONFIG_ACCOUNT_NAME;
    
    private static String CONFIG_ACCOUNT_PASSWORD;
    
    private static String CONFIG_GCAL_SERVICE_URL;
    
    private static String CONFIG_GCAL_EXCLUDE;
    
    private static String CONFIG_GCAL_CHECK_INTERVAL;
    
    private static String CONFIG_GCAL_PROXY_HOST;
    
    private static String CONFIG_GCAL_PROXY_PORT;
    
    public static void main(String [] args) throws Exception
    {
        System.out.println("Starting GCal Notify Tracker...");

        loadConfig();

        System.setProperty("http.proxyHost", CONFIG_GCAL_PROXY_HOST);
        System.setProperty("http.proxyPort", CONFIG_GCAL_PROXY_PORT);        
        System.setProperty("https.proxyHost", CONFIG_GCAL_PROXY_HOST);
        System.setProperty("https.proxyPort", CONFIG_GCAL_PROXY_PORT);        
        
        // load the events to exclude
        if ( CONFIG_GCAL_EXCLUDE == null )
            error("Event exclude list is not defined, will not exclude any events.");
        else
            exclude = CONFIG_GCAL_EXCLUDE.split("\\|");

        // all startup initialization is complete, enter loop
        try
        {
            checkInterval = Integer.parseInt(CONFIG_GCAL_CHECK_INTERVAL);
        }
        catch (Throwable t)
        {
            error("Interval check parameter is not a number, using default of "+checkInterval+" seconds", t);
        }
        while ( true )
        {
            check();
            try
            {
                System.out.println("\nCheck completed, sleeping...");
                Thread.sleep(checkInterval*1000);
            }
            catch (Throwable t)
            {
                error("Wait period has been interrupted, exiting.", t);
                return;
            }
        }
    }
    
    private static void loadConfig() throws Exception
    {
        CONFIG_ACCOUNT_NAME = NotifyTrackerConfig.getConfiguration().getProperty(NotifyTrackerConfig.CONFIG_ACCOUNT_NAME);
        CONFIG_ACCOUNT_PASSWORD = NotifyTrackerConfig.getConfiguration().getProperty(NotifyTrackerConfig.CONFIG_ACCOUNT_PASSWORD);
        CONFIG_GCAL_SERVICE_URL = NotifyTrackerConfig.getConfiguration().getProperty(NotifyTrackerConfig.CONFIG_GCAL_SERVICE_URL);
        CONFIG_GCAL_EXCLUDE = NotifyTrackerConfig.getConfiguration().getProperty(NotifyTrackerConfig.CONFIG_GCAL_EXCLUDE);
        CONFIG_GCAL_CHECK_INTERVAL = NotifyTrackerConfig.getConfiguration().getProperty(NotifyTrackerConfig.CONFIG_GCAL_CHECK_INTERVAL);
        CONFIG_GCAL_PROXY_HOST = NotifyTrackerConfig.getConfiguration().getProperty(NotifyTrackerConfig.CONFIG_GCAL_PROXY_HOST);
        CONFIG_GCAL_PROXY_PORT = NotifyTrackerConfig.getConfiguration().getProperty(NotifyTrackerConfig.CONFIG_GCAL_PROXY_PORT);
        
        // massage some of the data to allow for some user errors
        if ( CONFIG_GCAL_SERVICE_URL.charAt(CONFIG_GCAL_SERVICE_URL.length()-1) != '/' )
            CONFIG_GCAL_SERVICE_URL += "/";

        /**
        System.out.println("CONFIG_ACCOUNT_NAME: "+CONFIG_ACCOUNT_NAME);
        System.out.println("CONFIG_ACCOUNT_PASSWORD: "+CONFIG_ACCOUNT_PASSWORD);
        System.out.println("CONFIG_GCAL_SERVICE_URL: "+CONFIG_GCAL_SERVICE_URL);
        System.out.println("CONFIG_GCAL_EXCLUDE: "+CONFIG_GCAL_EXCLUDE);
        System.out.println("CONFIG_GCAL_CHECK_INTERVAL: "+CONFIG_GCAL_CHECK_INTERVAL);
        System.out.println("CONFIG_GCAL_PROXY_HOST: "+CONFIG_GCAL_PROXY_HOST);
        System.out.println("CONFIG_GCAL_PROXY_PORT: "+CONFIG_GCAL_PROXY_PORT);
        **/
    }
    
    private static void check() throws Exception
    {
        System.out.println("Starting event scan...");
        
        // start the batch counter
        int batchCounter = 0;

        // log the user in
        CalendarService myService = new CalendarService(APPLICATION_NAME);
        myService.setUserCredentials(CONFIG_ACCOUNT_NAME, CONFIG_ACCOUNT_PASSWORD);
        
        // get all the calendars 
        URL calFeedUrl = new URL(CONFIG_GCAL_SERVICE_URL+"default/owncalendars/full");
        CalendarFeed calResultFeed = myService.getFeed(calFeedUrl, CalendarFeed.class);

        // go through all of them
        for ( CalendarEntry calEntry : calResultFeed.getEntries() )
        {
            System.out.println("Scanning calendar: "+calEntry.getId());

            // get all owned events after now
            URL feedUrl = new URL(calEntry.getLink("alternate", "application/atom+xml").getHref());
    
            CalendarQuery query = new CalendarQuery(feedUrl);
            query.setMinimumStartTime(DateTime.now());
    
            // Send the request and receive the response:
            CalendarEventFeed resultFeed = myService.query(query, CalendarEventFeed.class);
                    
            // filter based on the calendars to be tracked
            ArrayList<CalendarEventEntry> calList = new ArrayList<CalendarEventEntry >();
            System.out.println("Starting event exclude check...");
            for ( int i = 0; i < resultFeed.getEntries().size(); i++ )
            {
                CalendarEventEntry entry = resultFeed.getEntries().get(i);
    
                for ( int j = 0; j < exclude.length; j++ )
                {
                    String entryTitle = entry.getTitle().getPlainText().toLowerCase().trim();
                    if ( !exclude[j].toLowerCase().equals(entryTitle) )
                        calList.add(entry);
                    else
                        System.out.println("Excluded entry: "+entryTitle);
                }
            }
            System.out.println("Completed event exclude check.");
            
            // ok, have all the events, check to see if there is an SMS notification
            for ( CalendarEventEntry entry : calList )   
            {
                System.out.println("\nChecking event "+entry.getTitle().getPlainText()+" for SMS reminder");
                List<Reminder> reminders = entry.getReminder();
                
                boolean foundSMSReminder = false;
                for ( Reminder reminder : reminders )
                {
                    if ( reminder.getMethod().equals(Method.SMS) )
                    {
                        System.out.println("Reminder method for this event: "+reminder.getMethod());
                        System.out.println("Event already has SMS reminder");
                        foundSMSReminder = true;
                        break;
                    }
                }
                
                if ( !foundSMSReminder )
                {
                    System.out.println("No SMS reminder found for this event.");
                   
                    // if the event is before 10am, set the reminder to be 13 hours before
                    List<When> times = entry.getTimes();
                    
                    // only care about the first "When"
                    long startTime = times.get(0).getStartTime().getValue();
                    Calendar startCal = Calendar.getInstance();
                    startCal.setTime(new Date(startTime));
                    System.out.println("Event start time is "+times.get(0).getStartTime().toString());
                    System.out.println("Event start hour is "+startCal.get(Calendar.HOUR_OF_DAY));
                    
                    Reminder smsReminder = new Reminder();
                    if ( startCal.get(Calendar.HOUR_OF_DAY) < 10 )
                    {
                        System.out.println("Event starts before 10AM, setting reminder to 13 hours before");
                        smsReminder.setHours(13);
                        smsReminder.setMethod(Method.SMS);
                    }
                    else
                    {
                        System.out.println("Event starts after 10AM, setting reminder to 15 minutes before");
                        smsReminder.setMinutes(15);
                        smsReminder.setMethod(Method.SMS);
                    }
                    entry.getReminder().add(smsReminder);
                    entry.update();
                    System.out.println("Event has been updated.");
                }
            }
        }
    }
    
    private static void error(String message, Throwable t)
    {
        System.out.println("Unrecoverable erros: "+message);
        
        if ( t != null )
            t.printStackTrace();
    }
    
    private static void error(String message)
    {
        error(message, null);
    }
}
